Sistemas Operacionais

Thiago Pires

Fundamentos de Sistemas Operacionais


A função do sistema operacional é fornecer aos programas do usuário um modelo do computador melhor, mais simples e mais limpo, assim como lidar com o gerenciamento de todos os recursos mencionados. A maioria dos computadores tem dois modos de operação: modo núcleo e modo usuário.

Fundamentos de Sistemas Operacionais


O sistema operacional opera em modo núcleo (também chamado modo supervisor). Nesse modo, ele tem acesso completo a todo o hardware e *pode executar qualquer instrução que a máquina for capaz de executar.*


Observe, na figura a seguir, uma visão geral simplificada dos principais componentes:

Fundamentos de Sistemas Operacionais


O resto do software opera em modo usuário, no qual apenas um subconjunto das instruções da máquina está disponível.

A diferença entre os modos exerce papel crucial na maneira como os sistemas operacionais funcionam.

Os sistemas operacionais são enormes, complexos e têm vida longa. O código-fonte do coração de um sistema operacional como Linux ou Windows tem cerca de cinco milhões de linhas.

O que é um sistema operacional?


Os sistemas operacionais realizam duas funções essencialmente não relacionadas: (1) fornecer a programadores de aplicativos (e programas aplicativos, claro) um conjunto de recursos abstratos limpo em vez de recursos confusos de hardware, e (2) gerenciar esses recursos de hardware

O que é um sistema operacional?


Sistemas operacionais transformam o feio em belo, como mostrado na figura:

Usando essa abstração, os programas podem criar, escrever, ler arquivos, sem ter que lidar com detalhes complexos de como o hardware funciona

O que é um sistema operacional?


O conceito de um sistema operacional como fundamentalmente fornecendo abstrações para programas aplicativos é uma visão top-down (abstração de cima para baixo). Uma visão alternativa, bottom-up (abstração de baixo para cima), sustenta que o sistema operacional está ali para gerenciar todas as partes de um sistema complexo.

O que é um sistema operacional?


O gerenciamento de recursos inclui a multiplexação (compartilhamento) de recursos de duas maneiras diferentes: no tempo e no espaço.

  • Quando um recurso é multiplexado no tempo, diferentes programas ou usuários se revezam usando-o.
  • O outro tipo é a multiplexação de espaço. Em vez de os clientes se revezarem, cada um tem direito a uma parte do recurso.

O que é um sistema operacional?


  1. Quando múltiplas saídas de impressão estão na fila para serem impressas em uma única impressora, uma decisão tem de ser tomada sobre qual deve ser impressa em seguida.

Multiplexado no tempo

  1. Em vez de os clientes se revezarem, cada um tem direito a uma parte do recurso. Por exemplo, a memória principal é normalmente dividida entre vários programas sendo executados, de modo que cada um pode ser residente ao mesmo tempo (por exemplo, a fim de se revezar usando a CPU).

Multiplexado no espaço

Revisão sobre hardware de computadores


Um sistema operacional está intimamente ligado ao hardware do computador no qual ele é executado


A CPU, memória e dispositivos de E/S estão todos conectados por um sistema de barramento (bus) e comunicam-se uns com os outros sobre ele.

Revisão sobre hardware de computadores


Processadores

O “cérebro” do computador é a CPU. O ciclo básico de toda CPU é buscar a primeira instrução da memória, decodificá-la para determinar o seu tipo e operandos, executá-la.


Cada CPU tem um conjunto específico de instruções que ela consegue executar. Desse modo, um processador x86 não pode executar programas ARM.

As CPUs têm alguns registradores internos para armazenamento de variáveis e resultados temporários.

Os resgistradores são importantes por causa da multiplexação de tempo da CPU.

Revisão sobre hardware de computadores


Memória

É o segundo principal componente em qualquer computador, o qual deve ser rápido ao extremo (mais rápida do que executar uma instrução, de maneira que a CPU não seja atrasada pela memória).


Memória

A camada superior consiste em registradores internos à CPU. Eles são feitos do mesmo material que a CPU e são, desse modo, tão rápidos quanto ela

Memória cache é uma parte da CPU. Atua como memória temporária para que seja recuperado rapidamente os dados, sem a necessidade de uma busca direta na memória principal

Mémoria principal tem por finalidade o armazenamento de instruções e dados de programas que serão ou estão sendo executados pela CPU.

Discos magnéticos são um tipo de memória não volátil de grande capacidade de armazenamento, usada para guardar informações (instruções e dados de programas) que não serão imediatamente usadas pela CPU.

Exemplo de utilização de cache


DuckDB tem uma forma de consulta (vectorized or just-in-time query execution engines) que são processadas em lotes de dados que consistem em coleções de vetores, cada um contendo uma quantidade fixa de valores das colunas.

O resultado é um uso eficiente das operações no cache, mantendo os dados nas consultas tanto quanto possível no cache L1 e L2 muito rápido.

O zoológico dos sistemas operacionais

  • Sistemas operacionais de computadores de grande porte, de alto desempenho e alta disponibilidade (mainframes)
  • Sistemas operacionais de servidores
  • Sistemas operacionais de computadores pessoais
  • Sistemas operacionais de computadores portáteis
  • Sistemas operacionais embarcados
  • Sistemas operacionais de tempo real

Conceitos de sistemas operacionais

  • Processos: [um processo é basicamente um programa em execução].marked e associado a cada processo está um espaço de endereçamento, uma lista de posições de mémoria que vai de 0 a algum máximo, onde o processo pode ler e escrever.
  • Espaços de endereçamento: diz respeito ao gerenciamento e à proteção da memória principal do computador, quando se tem multiplos processos sendo executados.
  • Arquivos: um sistema de arquivos é uma estrutura usada por um sistema operacional para organizar e gerenciar arquivos em um dispositivo de armazenamento. Chamadas do sistemas são necessárias para criar, remover, ler escrever arquivos. Existe o conceito de diretório como uma maneira de agrupar os arquivos

Conceitos de sistemas operacionais

  • Entrada/Saída: o sistema operacional tem um subsistema de E/S para gerenciamento dos dispositivos.
  • Proteção: o sistema operacional gerencia a segurança do sistema de maneira que os arquivos, por exemplo, sejam acessíveis somente por usuários autorizados.
  • Interpretador de comandos (shell): é a principal interface entre um usuário e o sistema operacional.

Conceitos de sistemas operacionais

Memória virtual: A memória virtual proporciona a capacidade de executar programas maiores do que a memória física da máquina, rapidamente movendo pedaços entre a memória RAM e o disco.


Quando se instala o linux é possível definir o tamanho da partição do disco que será utilizado pela memória virtual (swap).

Chamadas de sistema

Já vimos que os sistemas operacionais apresentam duas funções: abstrações para os usuários e gerenciamento de recursos.

  • A parte do gerenciamento de recursos fica transparente para os usuários e é feita automaticamente.
  • Na sua maior parte a interação entre programas de usuários e o sistema operacional lida com as abstrações.

Chamadas de sistema


A manipulação de uma aplicação de usuário que invoca a chamada de sistema open()
  1. A função open() é executada em modo usuário
  2. No modo núcleo/kernel é feita uma busca em um vetor de endereços a implementação da chamada open()
  3. O open() é executado e retorna o resultado para o sistema operacional e sequencialmente para o usuário

Chamadas de sistema

API: elemento que proporciona uma ligação física ou lógica entre dois sistemas ou partes de um sistema que não poderiam ser conectados diretamente.

  • API define um conjunto de normas que possibilita a comunicação entre plataformas por meio de uma série de padrões e protocolos.
  • Por meio de APIs, desenvolvedores podem criar novos softwares e aplicativos capazes de se comunicar com outras plataformas. Por exemplo: caso um desenvolvedor queira criar um aplicativo de fotos para Android, ele poderá ter acesso à câmera do celular através da API do sistema operacional, sem ter a necessidade de criar uma nova interface de câmera do zero..


Aqui uma abstração da complexidade!

Chamadas de sistema

As chamadas de sistema sempre foram o meio pelo qual os programas de espaço do usuário podem acessar os serviços do kernel

graph LR;
    subgraph U[Usuário]
    A[Função: mkdir] --> B[Interface de Chamada de Sistema: sys_mkdir];

    end
    subgraph K[Kernel]
    B --> C[Manipulador de Chamada de Sistema];
    end

    style U fill:#ffffff
    style K fill:#e4e4e4


  • Cria um novo diretório (pasta)
mkdir mynewdir
  • Visualizar a interface de chamada
cat /usr/include/asm*/unistd.h | grep -B 1 sys_mkdir
#define __NR_mkdirat 34
__SYSCALL(__NR_mkdirat, sys_mkdirat)
  • Visualizar os registradores onde são armazenados as info da chamada
cpuid -1 -r | head
CPU:
   0x00000000 0x00: eax=0x0000000d ebx=0x756e6547 ecx=0x6c65746e edx=0x49656e69
   0x00000001 0x00: eax=0x000406f0 ebx=0x01020800 ecx=0xfefa3203 edx=0x1f8bfbff

Chamadas de sistema

Uma chamada de sistem pode necessitar de outras chamadas serem realizadas

strace -c mkdir mynewdir
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
  0.00    0.000000           0         5           read
  0.00    0.000000           0         8           close
  0.00    0.000000           0        18           mmap
  0.00    0.000000           0         7           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         3           brk
  0.00    0.000000           0         4           pread64
  0.00    0.000000           0         2         2 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           mkdir
  0.00    0.000000           0         2         2 statfs
  0.00    0.000000           0         2         1 arch_prctl
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0        26        20 openat
  0.00    0.000000           0        26        20 newfstatat
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0         1           prlimit64
  0.00    0.000000           0         1           getrandom
  0.00    0.000000           0         1           rseq
------ ----------- ----------- --------- --------- ----------------
100.00    0.000000           0       111        45 total

Chamadas de sistema


Os desenvolvedores de aplicações projetam programas de acordo com uma interface de programação de aplicações (API — application programming interface).

A API especifica um conjunto de funções que estão disponíveis para um programador de aplicações, incluindo os parâmetros que são passados a cada função e os valores de retorno que o programador pode esperar.

Portable Operating System Interface (POSIX) é uma API para o sistema UNIX/Linux.

Se usarmos o comando ps, ele deverá se comportar da mesma forma no OpenBSD, Debian e macOS.

Chamadas de sistema


  • Uso da função write em C++
write.cpp
#include<unistd.h>

int main() 
{
    write(1, "Ola Mundo!", 10);
}
  • Nas linguagens de programação C e C++, unistd.h é o nome do arquivo de cabeçalho que fornece acesso à API do sistema operacional POSIX.
  • Compilar: g++ write.cpp
  • Executar: ./a.out

Chamada de sistema


Abaixo a chamada de sistema write sendo utilizada

strace -o trace.txt ./a.out

cat trace.txt | grep -A 5 write
write(1, "Ola Mundo!", 10)              = 10
exit_group(0)                           = ?
+++ exited with 0 +++

Chamada de sistema


No fim das contas um printf realiza a mesma chamada de sistema write

write.cpp
#include<stdio.h>

int main() 
{
    printf("Ola Mundo!");
}
strace -o trace.txt ./a.out

cat trace.txt | grep -A 5 write
write(1, "Ola Mundo!", 10)              = 10
exit_group(0)                           = ?
+++ exited with 0 +++

Chamada de sistema


strace -o trace.txt python -c 'print("Ola Mundo!")'

cat trace.txt | grep -A 5 write 
  • Será realizada a chamada de sistema write?
  • Comparar com as chamadas de sistema feitas com C++

Chamadas de sistema

  • Chamadas de sistema para gerenciamento de processos
  • Chamadas de sistema para gerenciamento de arquivos
  • Chamadas de sistema para gerenciamento de diretórios
  • Chamadas de sistema diversas

Chamadas de sistema para gerenciamento de processos


Chamada Descrição
pid = fork() Criar um processo filho idêntico ao pai
pid = waitpid(pid, statloc, options) Espera que um processo filho seja concluído
s = execve(name, argv, environp) Substitui a imagem do núcleo de um processo
exit(status) Conclui a execução do processo e devolve status

Chamadas de sistema para gerenciamento de processos

fork

fork_exemplo.cpp
#include <stdio.h>
#include <unistd.h>

int main()
{
    // make two process which run same
    // program after this instruction
    pid = fork();
    if(pid < 0){
    perror("fork fail");
    _exit(1);
    }
    printf("Hello world!, process_id(pid) = %d \n", getpid());
    return 0;
}


Hello world!, process_id(pid) = 685 
Hello world!, process_id(pid) = 686

Chamadas de sistema para gerenciamento de processos

waitpid

waitpid_exemplo.cpp
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int i = 1;
int pid;
int waitpid_return;
int main ()
{   
    printf("process_id(pid) parent= %d\n", getpid());
    pid = fork();
    if (pid != 0)
    {   
      
      for (int i = 1; i < 5; i++) {
        waitpid_return = waitpid(pid, NULL, WNOHANG);
        printf("%d, process_id(pid) child = %d, waitpid = %d\n", i, pid, waitpid_return);
      }
    }
    else {
        waitpid_return = waitpid(pid, NULL, WNOHANG);
        printf("%d, process_id(pid) child = %d, waitpid = %d\n", i, pid, waitpid_return);}
        return 0;
    }

Chamadas de sistema para gerenciamento de processos

execve

#include <unistd.h>
#include <iostream>
#include <string>

std::string c = "/bin/ls";
std::string p = "-lh";
char *args[] = {c.data(), p.data()};
int main() {
  execve(args[0], args, NULL);
}

Chamadas de sistema para gerenciamento de diretórios


Chamada Descrição
s = mkdir(name, mode) Cria um novo diretório
s = rmdir(name) Remove um diretório
s = link(name1, name2) Cria um nova entrada name1 apontando para name2
s = unlike(name) Remove uma entrada de diretório
s = mount(special, name, flag) Monta um sistema de arquivos
s = unmount(special) Desmonta um sistema de arquivos

Chamadas de sistema para gerenciamento diversos


Chamada Descrição
s = chdir(dirname) Altera o diretório de trabalho
s = chmod(name, mode) Altera os bits de proteção de um arquivo
s = kill(pid, signal) Envia um sinal para um processo

Estruturas do Sistema Operacional

Os sistemas operacionais podem ser organizados de várias maneiras, dependendo de sua estrutura interna e de como eles gerenciam os recursos do computador.

Monolítico


  • Nesta estrutura, todo o sistema operacional é implementado como um único programa de grande porte.
  • Todas as funcionalidades do sistema operacional, como gerenciamento de memória, gerenciamento de processos e sistemas de arquivos, residem no kernel.
  • Exemplos incluem sistemas operacionais mais antigos, como MS-DOS e versões mais antigas do UNIX.

Microkernel


  • Neste modelo, o kernel é mínimo e fornece apenas as funcionalidades básicas, como gerenciamento de memória, comunicação entre processos e escalonamento de CPU.
  • Funcionalidades adicionais, como sistemas de arquivos e drivers de dispositivos, são implementadas como processos de usuário que se comunicam com o kernel.
  • Exemplos incluem o MINIX e o Symbian.

Desse modo, um erro no driver de áudio fará que o som fique truncado ou pare, mas não derrubará o computador.

Híbrido


  • Esta abordagem combina elementos do kernel monolítico e do microkernel.
  • O kernel contém algumas funcionalidades essenciais, como gerenciamento de memória e escalonamento de processos, enquanto outras funcionalidades são implementadas como módulos do kernel ou como processos de usuário.
  • Exemplos incluem Linux, Windows NT/2000/XP/Vista/7/8/10.

Sistemas Virtuais


  • Esta estrutura cria uma máquina virtual que simula uma arquitetura de hardware para cada processo.
  • Cada processo tem a ilusão de que possui seu próprio sistema operacional.
  • Exemplos incluem máquinas virtuais como VMware, VirtualBox e Hyper-V.

(a) Um hipervisor de tipo 1. (b) Um hipervisor de tipo 2 puro. (c) Um hipervisor de tipo 2 na prática.

Gerenciamento de processos

O conceito mais central em qualquer sistema operacional é o processo: uma abstração de um programa em execução.

Processos

  • Um processo é apenas uma instância de um programa em execução, incluindo os valores atuais do contador do programa, registradores e variáveis.
  • Processos podem ser criados e terminados dinamicamente.
  • Cada processo tem seu próprio espaço de endereçamento.

O modelo de processo

  1. Vemos um computador multiprogramando quatro programas na memória.
  2. Vemos quatro processos, cada um com seu próprio fluxo de controle e sendo executado independente dos outros.
  3. Vemos que, analisados durante um intervalo longo o suficiente, todos os processos tiveram progresso, mas a qualquer dado instante apenas um está sendo de fato executado.


Criação de processos

Sistemas operacionais precisam de alguma maneira para criar processos.

Quatro eventos principais fazem com que os processos sejam criados:

Inicialização do sistema. Alguns processos são de (1) primeiro plano, sendo processos que interagem com o usuário; (2) segundo plano, processos que não estão associados a um usuário (daemons)

Execução de uma chamada de sistema de criação de processo por um processo em execução. Um processo em execução emitirá chamadas de sistema para criar processos novos para ajudá-lo em seu trabalho

Solicitação de um usuário para criar um novo processo. Em sistemas interativos, os usuários podem começar um programa digitando um comando ou clicando duas vezes sobre um ícone.

Início de uma tarefa em lote. Pense no gerenciamento de estoque ao fim de um dia em uma cadeia de lojas, nesse caso usuários podem submeter tarefas em lote ao servidor (possivelmente de maneira remota).

Criação de processos

No UNIX, há apenas uma chamada de sistema para criar um novo processo: fork. Essa chamada cria um clone exato do processo que a chamou. Após a fork, os dois processos, o pai e o filho, têm a mesma imagem de memória, as mesmas variáveis de ambiente e os mesmos arquivos abertos. Mas atuam de forma independente.

Como identificar processos filho?

child.sh
!/bin/bash
sleep infinity
parent.sh
!/bin/bash
./child.sh &
sleep infinity
$
parent.sh &

Usando:

$
pgrep -P <parent pid>
pgrep -lP <parent pid>
pstree -p <parent pid>
ps --ppid <parent pid>
ls /proc/<parent pid>/task
cat /proc/<parent pid>/task/<parent pid>/children

Término de processos

Após um processo ter sido criado, ele começa a ser executado e realiza qualquer que seja o seu trabalho. No entanto, nada dura para sempre, nem mesmo os processos. Cedo ou tarde, o novo processo terminará, normalmente devido a uma das condições a seguir:

  1. Saída normal (voluntária).
  2. Erro fatal (involuntário).
  3. Saída por erro (voluntária).
  4. Morto por outro processo (involuntário).

Exemplos:

  1. ctrl + c para interromper programas ou processos no primeiro plano
  2. !g++ foo.cpp e foo.cpp não existe no diretório
  3. Um Erro interno do processo que afeta seu funcionamento, então o usuário é avisado e o programa termina
  4. kill <pid>

Hierarquias de processos

  • Em alguns sistemas, quando um processo cria outro, o processo pai e o processo filho continuam a ser associados de certas maneiras.
  • O processo filho pode em si criar mais processos, formando uma hierarquia de processos.
$
./grandparent.sh
ps -efj | egrep "PGID|children|parent"
kill -9 -<pgid>
grandparent.sh
#!/bin/bash
bash parent.sh &
bash parent.sh &
for i in {1..100}; do 
sleep 2; 
echo -n "This is the grandparent process $i"; 
done
parent.sh
#!/bin/bash
bash children.sh &
bash children.sh &
for i in {1..100}; do sleep 2; echo -n "This is the parent process $i"; 
done
children.sh
#!/bin/bash
for i in {1..100}; do 
sleep 2; 
echo -n "This is a test in children process $i"; 
done

Estados de processos


  • Embora cada processo seja uma entidade independente, com seu próprio contador de programa e estado interno, processos muitas vezes precisam interagir entre si.
  • Um processo pode gerar alguma saída que outro processo usa como entrada.


$
curl -s https://openbible.com/textfiles/kjv.txt | \
grep "Exodus\s2" | \
head -4

São 3 Estados:

  • Em execução (realmente usando a CPU naquele instante).
  • Pronto (executável, temporariamente parado para deixar outro processo ser executado).
  • Bloqueado (incapaz de ser executado até que algum evento externo aconteça).

Estados de processos


  1. O processo é bloqueado aguardando uma entrada
  2. O escalonador seleciona outro processo
  3. O escalonador seleciona esse processo
  4. A entrada torna-se disponível

Um processo pode estar nos estados em execução, bloqueado ou pronto. Transições entre esses estados ocorrem como mostrado.

Estados de processos

O nível mais baixo de um sistema operacional estruturado em processos controla interrupções e escalonamento. Acima desse nível estão processos sequenciais.

O escalonamento, isto é, decidir qual processo deve ser executado, quando e por quanto tempo, é um assunto importante; nós o examinaremos mais adiante neste capítulo. Muitos algoritmos foram desenvolvidos para tentar equilibrar as demandas concorrentes de eficiência para o sistema como um todo e justiça para os processos individuais.

Implementação de processos

Para implementar o modelo de processos, o sistema operacional mantém uma tabela (um arranjo de estruturas) chamada de tabela de processos, com uma entrada para cada um deles.

  • Essas entradas contêm informações importantes sobre o estado do processo quando ele é trocado do estado em execução para pronto ou bloqueado
  • Podendo o processo retornar precisamente para o mesmo estado em que se encontrava antes de ser interrompido.

Alguns dos campos de uma entrada típica na tabela de processos

Threads


Cada processo tem um espaço de endereçamento e um único thread de controle. Na realidade, essa é quase a definição de um processo. Não obstante isso, em muitas situações, é desejável ter múltiplos threads de controle no mesmo espaço de endereçamento executando em quase paralelo, como se eles fossem (quase) processos separados (exceto pelo espaço de endereçamento compartilhado).

Threads, miniprocessos


Por que alguém iria querer ter um tipo de processo dentro de um processo? Na realidade, há várias razões para a existência desses miniprocessos, chamados threads

A capacidade para as entidades em paralelo compartilharem um espaço de endereçamento e todos os seus dados entre si.

São mais leves do que os processos, eles são mais fáceis (isto é, mais rápidos) para criar e destruir do que os processos.

Quando há uma computação substancial e também E/S substancial, contar com threads permite que essas atividades se sobreponham.

Threads são úteis em sistemas com múltiplas CPUs, onde o paralelismo real é possível.

Um processador de texto com três threads


Um thread interage com o usuário e o outro lida com a reformatação em segundo plano. Tão logo a frase é apagada da página 1, o thread interativo diz ao de reformatação para reformatar o livro inteiro. Enquanto isso, o thread interativo continua a ouvir o teclado e o mouse e responde a comandos simples como rolar a página 1 enquanto o outro thread está trabalhando com afinco no segundo plano. Um terceiro thread pode fazer backups de disco sem interferir nos outros dois.

Um processador de texto com três threads


Deve ficar claro que ter três processos em separado não funcionaria aqui, pois todos os três threads precisam operar no documento. Ao existirem três threads em vez de três processos, eles compartilham de uma memória comum.

O modelo de thread clássico


  1. vemos três processos tradicionais. Cada processo tem seu próprio espaço de endereçamento e um único thread de controle. Cada um deles opera em um espaço de endereçamento diferente.
  2. vemos um único processo com três threads de controle. Embora em ambos os casos tenhamos três threads. Todos os três compartilham o mesmo espaço de endereçamento.

Todo thread pode acessar todo espaço de endereçamento de memória dentro do espaço de endereçamento do processo, um thread pode ler, escrever, ou mesmo apagar a pilha de outro thread. Não há proteção, porque (1) é impossível e (2) não seria necessário.

Threads POSIX


Para possibilitar que se escrevam programas com threads portáteis, o IEEE definiu um padrão para threads no padrão IEEE 1003.1c. O pacote de threads que ele define é chamado Pthreads.

Todos os threads têm determinadas propriedades. Cada um tem um identificador, um conjunto de registradores (incluindo o contador de programa), e um conjunto de atributos, que são armazenados em uma estrutura.

Algumas das chamadas de função do Pthreads:

Executando Threads


multiple_threads.py

"""
Executando Múltiplas Threads

https://realpython.com/intro-to-python-threading/
"""

import logging
import threading
import time

def thread_function(name):
    logging.info("Thread %s: starting, ID: %s", name, threading.get_native_id())
    time.sleep(2)
    logging.info("Thread %s: finishing", name)

if __name__ == "__main__":
    format = "%(asctime)s: %(message)s"
    logging.basicConfig(format=format, level=logging.INFO,
                        datefmt="%H:%M:%S")

    threads = list()
    for index in range(3):
        logging.info("Main    : create and start thread %d.", index)
        x = threading.Thread(target=thread_function, args=(index,))
        threads.append(x)
        x.start()

    for index, thread in enumerate(threads):
        logging.info("Main    : before joining thread %d.", index)
        thread.join()
        logging.info("Main    : thread %d done", index)

Convertendo de um thread para multithread

Conflitos entre threads sobre o uso de uma variável global


Conflitos entre threads sobre o uso de uma variável global.

Threads podem ter variáveis globais individuais.